
#include "modbus_client.hpp"

#include "app.hpp"
#include "between_face_common.hpp"
#include "oled.hpp"
using namespace beef;


const ioxx::Pin RS485_DE_RE_PIN = RS485_DE_RE_PIN_NUM;  // 485 收发器的DE/RE# 引脚


modpash::NonBlockSerialFrameHandler mp{TimeSource{}, Serial485, RS485_DE_RE_PIN};
modpash::BasicClient mp_client{mp};


void init_modbus_client(uint32_t baud) {
    Serial485.begin(baud);
    mp_client.set_response_timeout(MODBUS_COUNT_TIMEOUT);  // 设置响应超时时间
    pinMode(RS485_DE_RE_PIN, OUTPUT);                      // 设置RS485 DE/RE# 引脚为输出模式
    mp.clear();
}


void set_response_timeout(TimeType t) {
    mp_client.set_response_timeout(t);
}


int wait_flag(InterfaceBase *current_screen) {
    int flag;
    while ((flag = mp_client.response_available()) == 0) {
        // dcb.tick();  // 处理延时任务，避免阻塞
        current_screen->tick();
    }
    return flag;
}


void display_flag(int flag) {
    if (flag < 0) {
        if (mp_client.last_error() == modpash::error_level::response_timeout) {
            show_msg("TIMEOUT");
        }
        else if (mp_client.last_error() == modpash::error_level::response_mismatch) {
            show_msg("MISMATCH");
        }
        else {
            show_msg("ERROR");
        }
    }
    else {
        show_msg("OK");
    }
}


void show_exception(int code) {
    begin_msg();
    u8g2.print("E = ");
    u8g2.print(code);
    end_msg();
}


bool read_u16_from(InterfaceBase *current_screen, uint8_t slave, uint16_t address, uint16_t *dst, uint8_t count) {
    mp_client.begin(slave);  // 开始与指定从机通信

    auto start_at = millis();
    mp_client.request_read(address, count);
    // mp.clear_serial();   // 有必要在发送后清空串口缓冲区，
    int flag = wait_flag(current_screen);

    auto rx_time = millis() - start_at;

    show_response_time(rx_time);
    display_flag(flag);

    if (flag > 0) {
        int r = mp_client.check_response();

        if (r == count) {
            for (uint8_t i = 0; i < count; ++i) {
                dst[i] = mp_client.read_u16();
            }
        }
        else if (r < 0) {
            // 显示异常码
            show_exception(0 - r);
        }
        else {
            show_msg("ERR");
        }

        return true;
    }

    return false;  // 返回0表示读取失败
}


bool read_u32_from(InterfaceBase *current_screen, uint8_t slave, uint16_t address, uint32_t *dst) {
    uint16_t data[2];
    if (read_u16_from(current_screen, slave, address, data, 2)) {
        *dst = (static_cast<uint32_t>(data[0]) << 16) | data[1];
        return true;
    }
    return false;
}


bool write_u16_to(InterfaceBase *current_screen, uint8_t slave, uint16_t address, uint16_t value) {
    mp_client.begin(slave);  // 开始与指定从机通信

    auto start_at = millis();
    mp_client.request_write_u16(address, value);
    // mp.clear_serial();
    int flag = wait_flag(current_screen);

    auto rx_time = millis() - start_at;

    show_response_time(rx_time);
    display_flag(flag);

    if (flag > 0) {
        int r = mp_client.check_response();

        if (r == 1) {
            return true;  // 返回1表示写入成功
        }
        else if (r < 0) {
            // 显示异常码
            show_exception(0 - r);
        }
        else {
            show_msg("ERR");
        }
    }

    return false;
}